#pragma warning(disable : 4996)
#include "Matrix.h"
#include <iostream>
#include <ctime>
#include <cmath>
#include <qsortfilterproxymodel.h>



Matrix& Matrix:: operator = (const Matrix& m)
{
    if (m.data != data)
    {
        Free(data, height, width);
        Alloc(data, m.height, m.width);
        height = m.height;
        width = m.width;
        for (int i = 0; i < height; i++)
            for (int j = 0; j < width; j++) {
                for (int rgb = 0; rgb < 3; rgb++) {
                    data[i][j][rgb] = m.data[i][j][rgb];
                }
            }
    }
    return *this;
}

Matrix& Matrix:: operator= (const double a)
{
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            for (int rgb = 0; rgb < 3; rgb++) {
                data[i][j][rgb] = a;
            }
        }

    }
    return *this;
}

bool operator == (const Matrix& m, const Matrix& n)
{
    if (m.height == n.height && m.width == n.width)
    {
        for (int i = 0; i < m.height; i++)
            for (int j = 0; j < m.width; j++)
            {
                for (int rgb = 0; rgb < 3; rgb++) {
                    if (m.data[i][j][rgb] != n.data[i][j][rgb]) return false;
                }
            }
        return true;
    }
    else return false;
}

Matrix& Matrix::Normalize(int)
{
    double max = -256;
    double min = 256;
    double nowdataij = 0;
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            for (int rgb = 0; rgb < 3; rgb++) {
                nowdataij += data[i][j][rgb];
            }
            nowdataij /= 3;
            if (min >= nowdataij) min = nowdataij;
            if (max <= nowdataij) max = nowdataij;
            nowdataij = 0;
        }
    }

    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            for (int rgb = 0; rgb < 3; rgb++) {
                data[i][j][rgb] = 255 * (data[i][j][rgb] - min) / (max - min);
            }
        }
    }
    return *this;
}

void Matrix::DisNormalize()
{
    for (int i = 0; i < height; i++)
        for (int j = 0; j < width; j++)
            for (int rgb = 0; rgb < 3; rgb++) {
                data[i][j][rgb] *= 255;
            }

}

void Matrix::Alloc(double***& data, const int& height, const int& width)
{
    data = new double** [height];
    for (int i = 0; i < height; i++) {
        data[i] = new double* [width];
        for (int j = 0; j < width; j++) {
            data[i][j] = new double[3];
        }
    }
}

void Matrix::Free(double***& data, const int& height, const int& width)
{
    int i;
    int j;
    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            delete[]data[i][j];
        }
    }
    for (i = 0; i < height; i++) {
        delete[]data[i];
    }
    delete[]data;
}

Matrix::Matrix()
{
    height = 0;
    width = 0;
    data = nullptr;
}

Matrix::Matrix(int h, int w)
{
    height = h;
    width = w;
    if (width % 4 != 0)
        width = (width * 24 / 8 + 3) / 4 * 4 / 3;     //
    Alloc(data, height, width);
}

Matrix::Matrix(int h, int w, double val)
{
    height = h;
    width = w;
    if (width % 4 != 0)
        width = (width * 24 / 8 + 3) / 4 * 4 / 3;  //
    Alloc(data, height, width);
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++) {
            for (int rgb = 0; rgb < 3; rgb++) {
                data[i][j][rgb] = val;
            }
        }

    }
}

Matrix::Matrix(const Matrix& m)
{
    height = m.height;
    width = m.width;
    Alloc(data, height, width);
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++) {
            for (int rgb = 0; rgb < 3; rgb++) {
                data[i][j][rgb] = m.data[i][j][rgb];
            }
        }

    }
}

Matrix::~Matrix()
{
    Free(data, height, width);
}


int Matrix::Height()const
{
    return height;
}

int Matrix::Width()const
{
    return width;
}

int Matrix::Padding() const
{
    return padding;
}

void Matrix::Transpose()
{
    double*** temp = nullptr;
    int h = height;
    if (height % 4 != 0)
        h = (height * 24 / 8 + 3) / 4 * 4 / 3;
    Alloc(temp, width, height);
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            for (int rgb = 0; rgb < 3; rgb++) {
                temp[j][i][rgb] = data[i][j][rgb];
            }
        }
    }
    Free(data, height, width);
    int t = width;
    width = height;
    height = t;
    data = temp;
}

double& Matrix::At(int row, int col, int rgb)
{
    return data[row][col][rgb];
}

double& Matrix::At(int row, int col, int rgb) const
{
    return data[row][col][rgb];
}

void Matrix::Set(int row, int col, int rgb, double value)
{
    data[row][col][rgb] = value;
}

void Matrix::Set(double value)
{
    for (int i = 0; i < height; i++)
        for (int j = 0; j < width; j++) {
            for (int rgb = 0; rgb < 3; rgb++) {
                data[i][j][rgb] = value;
            }
        }
}


void Matrix::Normalize()
{
    double min = 256;
    double max = 0;
    double nowdataij = 0;
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            for (int rgb = 0; rgb < 3; rgb++) {
                nowdataij += data[i][j][rgb];
            }
            nowdataij /= 3;
            if (min >= nowdataij) min = nowdataij;
            if (max <= nowdataij) max = nowdataij;
            nowdataij = 0;
        }
    }
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++)
        {
            for (int rgb = 0; rgb < 3; rgb++) {
                if (data[i][j][rgb] == min)
                    data[i][j][rgb] = 0;
                else if (data[i][j][rgb] == max)
                    data[i][j][rgb] = 1;
                else
                    data[i][j][rgb] = (data[i][j][rgb] - min) / (max - min);
            }
        }
    }
}


void Matrix::Reshape(int h, int w)
{
    double*** temp = nullptr;
    Alloc(temp, h, w);
    int m = 0, n = 0;
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            for (int rgb = 0; rgb < 3; rgb++) {
                temp[m][n][rgb] = data[i][j][rgb];
            }
            n++;
            if (n == w)
            {
                n = 0;
                m++;
            }
        }
    }
    Free(data, height, width);
    width = w;
    height = h;
    data = temp;
}

bool Matrix::IsEmpty() const
{
    if (data == nullptr)
        return true;
    else return false;
}

bool Matrix::IsSquare() const
{
    if (height == width && height != 0)
        return true;
    else return false;
}

void Matrix::CopyTo(Matrix& m)
{
    m.height = height;
    m.width = width;
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
            m.data[i][j] = data[i][j];
    }
}



void Matrix::Cat(Matrix& m, int code)
{
    if (code == 0 || code == 1)        //上下拼接，0表示调用函数的对象所表示的图像在上方
    {
        int new_height = height + m.height;
        double*** temp = nullptr;
        Alloc(temp, new_height, width);
        int rgb;
        for (int i = 0; i < new_height; i++)
        {
            for (int j = 0; j < width; j++)
            {
                if (code == 0)
                {
                    if (i < height) {
                        for (rgb = 0; rgb < 3; rgb++) {
                            temp[i][j][rgb] = data[i][j][rgb];
                        }
                    }
                    else {
                        for (rgb = 0; rgb < 3; rgb++) {
                            temp[i][j][rgb] = m.data[i - height][j][rgb];
                        }
                    }
                }
                else {
                    if (i < m.height) {
                        for (rgb = 0; rgb < 3; rgb++) {
                            temp[i][j][rgb] = m.data[i][j][rgb];
                        }
                    }
                    else {
                        for (rgb = 0; rgb < 3; rgb++) {
                            temp[i][j][rgb] = data[i - m.height][j][rgb];
                        }
                    }
                }
            }
        }
        Free(data, height, width);
        data = temp;
        height = new_height;
    }
    else {                                               //左右拼接，3表示调用函数的对象所表示的图像在左侧
        int new_width = width + m.width;
        if (new_width % 4 != 0)
            new_width = (new_width * 24 / 8 + 3) / 4 * 4 / 3;
        double*** temp = nullptr;
        int rgb;
        Alloc(temp, height, new_width);
        for (int i = 0; i < height; i++)
        {
            for (int j = 0; j < new_width; j++)
            {
                if (code == 3)
                {
                    if (j < width) {
                        for (rgb = 0; rgb < 3; rgb++) {
                            temp[i][j][rgb] = data[i][j][rgb];
                        }
                    }

                    else {
                        for (rgb = 0; rgb < 3; rgb++) {
                            temp[i][j][rgb] = m.data[i][j - width][rgb];
                        }
                    }
                }
                else {
                    if (j < m.width) {
                        for (rgb = 0; rgb < 3; rgb++) {
                            temp[i][j][rgb] = m.data[i][j][rgb];
                        }
                    }

                    else {
                        for (rgb = 0; rgb < 3; rgb++) {
                            temp[i][j][rgb] = data[i][j - m.width][rgb];
                        }
                    }
                }
            }
        }
        Free(data, height, width);
        data = temp;
        width = new_width;
    }
}



void Swap(Matrix& a, Matrix& b)
{
    int temp = a.width;
    a.width = b.width;
    b.width = temp;

    temp = a.height;
    a.height = b.height;
    b.height = temp;

    double*** t = a.data;
    a.data = b.data;
    b.data = t;
}


double Mean(double**& temp, int row, int col, int filterSize)
{
    double sum = 0;
    for (int i = row - filterSize / 2; i <= row + filterSize / 2; i++)
        for (int j = col - filterSize / 2; j <= col + filterSize / 2; j++)
        {
            sum += temp[i][j];
        }
    return sum / (filterSize * filterSize);
}

void Matrix::MeanFilter(int filterSize)
{
    //int height = input.Height();
    //int width = input.Width();

    double*** temp = nullptr;                      //创建动态数组
    temp = new double** [height + filterSize - 1];
    for (int i = 0; i < height + filterSize - 1; i++)
    {
        temp[i] = new double* [width + filterSize - 1];
        for (int j = 0; j < width + filterSize - 1; j++)
            temp[i][j] = new double[3];
    }

    for (int i = 0; i < height + filterSize - 1; i++)  //给扩建后的数组赋值，即给边缘值赋值
    {
        for (int j = 0; j < width + filterSize - 1; j++)
        {
            if (i < filterSize / 2 || j < filterSize / 2 || i > height - 1 + filterSize / 2 || j > width - 1 + filterSize / 2)
            {
                temp[i][j][0] = 0;
                temp[i][j][1] = 0;
                temp[i][j][2] = 0;
            }
            //给边缘值赋值0
            else
            {
                temp[i][j][0] = this->data[i - filterSize / 2][j - filterSize / 2][0];//数组复制
                temp[i][j][1] = this->data[i - filterSize / 2][j - filterSize / 2][1];//数组复制
                temp[i][j][2] = this->data[i - filterSize / 2][j - filterSize / 2][2];//数组复制
            }
        }
    }

    double** temp_R = NULL;
    double** temp_G = NULL;
    double** temp_B = NULL;
    temp_R = new double* [height + filterSize - 1];
    temp_G = new double* [height + filterSize - 1];
    temp_B = new double* [height + filterSize - 1];
    for (int i = 0; i < height + filterSize - 1; i++)
    {
        temp_R[i] = new double[width + filterSize - 1];
        temp_G[i] = new double[width + filterSize - 1];
        temp_B[i] = new double[width + filterSize - 1];
    }
    for (int i = 0; i < height + filterSize - 1; i++)
    {
        for (int j = 0; j < width + filterSize - 1; j++)
        {
            temp_B[i][j] = temp[i][j][0]; //分出蓝色
            temp_G[i][j] = temp[i][j][1]; //分出绿色
            temp_R[i][j] = temp[i][j][2]; //分出红色
        }
    }


    for (int i = filterSize / 2; i < height + filterSize / 2; i++)    //均值滤波
        for (int j = filterSize / 2; j < width + filterSize / 2; j++)
        {

            this->data[i - filterSize / 2][j - filterSize / 2][0] = Mean(temp_B, i, j, filterSize);
            this->data[i - filterSize / 2][j - filterSize / 2][1] = Mean(temp_G, i, j, filterSize);
            this->data[i - filterSize / 2][j - filterSize / 2][2] = Mean(temp_R, i, j, filterSize);
        }

    for (int i = 0; i < height + filterSize - 1; i++)        //释放内存
    {
        for (int j = 0; j < width + filterSize - 1; j++)
            delete[]temp[i][j];
        delete[]temp[i];
    }
    delete[]temp;
    for (int i = 0; i < height + filterSize - 1; i++)
    {
        delete[]temp_R[i];
        delete[]temp_G[i];
        delete[]temp_B[i];
    }
    delete[]temp_R;
    delete[]temp_G;
    delete[]temp_B;
}

double Median(double**& temp, int row, int col, int filterSize);

void Matrix::MedianFilter(int filterSize)
{

    double*** temp = nullptr;
    temp = new double** [height + filterSize - 1];        //创建数组
    for (int i = 0; i < height + filterSize - 1; i++)
    {
        temp[i] = new double* [width + filterSize - 1];
        for (int j = 0; j < width + filterSize - 1; j++)
        {
            temp[i][j] = new double[3];
        }
    }

    for (int i = 0; i < height + filterSize - 1; i++)  //给扩建后的数组赋值，即给边缘值赋值
    {
        for (int j = 0; j < width + filterSize - 1; j++)
        {
            if (i < filterSize / 2 || j < filterSize / 2 || i > height - 1 + filterSize / 2 || j > width - 1 + filterSize / 2)
            {
                temp[i][j][0] = 0;
                temp[i][j][1] = 0;
                temp[i][j][2] = 0;
            }
            //给边缘值赋值0
            else
            {
                temp[i][j][0] = this->data[i - filterSize / 2][j - filterSize / 2][0];//数组复制
                temp[i][j][1] = this->data[i - filterSize / 2][j - filterSize / 2][1];//数组复制
                temp[i][j][2] = this->data[i - filterSize / 2][j - filterSize / 2][2];//数组复制
            }
        }
    }

    double** temp_R = nullptr;
    double** temp_G = nullptr;
    double** temp_B = nullptr;
    temp_R = new double* [height + filterSize - 1];
    temp_G = new double* [height + filterSize - 1];
    temp_B = new double* [height + filterSize - 1];
    for (int i = 0; i < height + filterSize - 1; i++)
    {
        temp_R[i] = new double[width + filterSize - 1];
        temp_G[i] = new double[width + filterSize - 1];
        temp_B[i] = new double[width + filterSize - 1];
    }

    for (int i = 0; i < height + filterSize - 1; i++)
    {
        for (int j = 0; j < width + filterSize - 1; j++)
        {
            temp_B[i][j] = temp[i][j][0]; //分出蓝色
            temp_G[i][j] = temp[i][j][1]; //分出绿色
            temp_R[i][j] = temp[i][j][2]; //分出红色
        }
    }

    for (int i = filterSize / 2; i < height + filterSize / 2; i++)    //中值滤波
        for (int j = filterSize / 2; j < width + filterSize / 2; j++)
        {
            this->data[i - filterSize / 2][j - filterSize / 2][0] = Median(temp_B, i, j, filterSize);
            this->data[i - filterSize / 2][j - filterSize / 2][1] = Median(temp_G, i, j, filterSize);
            this->data[i - filterSize / 2][j - filterSize / 2][2] = Median(temp_R, i, j, filterSize);
        }

    for (int i = 0; i < height + filterSize - 1; i++)        //释放内存
    {
        for (int j = 0; j < width + filterSize - 1; j++)
            delete[]temp[i][j];
        delete[]temp[i];
    }
    delete[]temp;
    for (int i = 0; i < height + filterSize - 1; i++)
    {
        delete[]temp_R[i];
        delete[]temp_G[i];
        delete[]temp_B[i];
    }
    delete[]temp_R;
    delete[]temp_G;
    delete[]temp_B;
}

double Median(double**& temp, int row, int col, int filterSize)
{
    int Dest = filterSize * (filterSize + 1) / 2 - (filterSize - 1) / 2;
    double* t = new double[filterSize * filterSize];
    int k = 0;
    for (int i = row - filterSize / 2; i <= row + filterSize / 2; i++)
        for (int j = col - filterSize / 2; j <= col + filterSize / 2; j++)
        {
            t[k++] = temp[i][j];
        }
    std::sort(t, t + filterSize * filterSize);//在qt里要包含头文件 #include<QtAlgorithms>
    return t[Dest - 1];
}

